
package com.whosly.mysql.protocol.packet.impl;

import com.whosly.mysql.protocol.jdbc.MySQLMessage;
import com.whosly.mysql.protocol.packet.jdbc.AbstractMySQLPacket;
import com.whosly.mysql.protocol.packet.util.NettyBufferUtil;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
import lombok.Setter;

/**
 * 结果集头部Packet
 *
 * <pre>
 *     Bytes                        Name
 *  -----                        ----
 *  1-9   (Length-Coded-Binary)  field_count
 *  1-9   (Length-Coded-Binary)  extra
 *
 *  field_count: See the section "Types Of Result Packets"
 *               to see how one can distinguish the
 *               first byte of field_count from the first
 *               byte of an OK Packet, or other packet types.
 *
 *  extra:       For example, SHOW COLUMNS uses this to send
 *               the number of rows in the table.
 * </pre>
 *
 *
 * @author fengyang(yueny09@163.com)
 */
public class ResultSetHeaderPacket extends AbstractMySQLPacket
{

    /**
     * 用于标识Field结构的数量，取值范围0x00-0xFA。
     */
    @Getter
    private int fieldCount;

    // 可选字段，一般情况下不应该出现。只有像SHOW COLUMNS这种语句的执行结果才会用到额外信息（标识表格的列数量）。
    @Setter
    @Getter
    private long extra;

    public ResultSetHeaderPacket(int fieldCount) {
        this.fieldCount = fieldCount;
    }

    public void read(byte[] data) {
        MySQLMessage mm = new MySQLMessage(data);
        setArgs(mm.readUB3(), mm.read());

        readBody(this, mm);
    }

    @Override
    public ByteBuf writeBuf(ByteBuf buffer) {
        int size = calcPacketSize();
        NettyBufferUtil.writeUB3(buffer, size);
        buffer.writeByte(getPackId());

        NettyBufferUtil.writeLength(buffer, fieldCount);
        if (extra >= 0) {
            NettyBufferUtil.writeLength(buffer, extra);
        }
        return buffer;
    }

    @Override
    public int calcPacketSize() {
        int size = NettyBufferUtil.getLength(fieldCount);
        if (extra >= 0) {
            size += NettyBufferUtil.getLength(extra);
        }
        return size;
    }

    @Override
    public String getPacketInfo() {
        return "MySQL ResultSetHeader Packet";
    }

    /**
     * 从 MySQLMessage 中构造 ResultSetHeaderPacket 对象
     */
    public static final ResultSetHeaderPacket of(final MySQLMessage mm) {
        ResultSetHeaderPacket headerPacket = new ResultSetHeaderPacket(0);

        headerPacket.setArgs(mm.readUB3(), mm.read());

        readBody(headerPacket, mm);

        return headerPacket;
    }

    private static void readBody(ResultSetHeaderPacket packet, MySQLMessage mm) {
        packet.fieldCount = (int) mm.readLength();
        if (mm.hasRemaining()) {
            packet.extra = mm.readLength();
        }
    }

}